#!/usr/bin/env python3
# coding: utf-8

"""
2024-08-08 F 运行在pi zero上的, 服务器管理工具
"""
import sys
import os
from pathlib import Path
import time
import threading
from gpiozero import LED, Buzzer, Button
from signal import pause
import datetime
import subprocess
import random

## sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from servermanagerutil import *
from servermanager import *

## IO口定义
# SERVER6
LED_S6_RED = LED(15)
LED_S6_GREEN = LED(18)
# SERVER7
LED_S7_RED = LED(4)
LED_S7_GREEN = LED(17)
# 演示
LED_DEMO_RED = LED(27)
LED_DEMO_GREEN = LED(22)
# 实施
LED_TEST_RED = LED(10)
LED_TEST_GREEN = LED(9)
# SERVER9
LED_S9_RED = LED(11)
LED_S9_GREEN = LED(5)
# 蜂鸣器
BEEP = Buzzer(26)
# 主板电源
LED_POWER_RED = LED(21)
LED_POWER_GREEN = LED(20)
BUTTON_POWER = Button(16)

# 开关: 手动控制
BUTTON_MANUAL_START = Button(8)
BUTTON_MANUAL_STOP = Button(7)
# 开关: 自动打开
BUTTON_AUTOON = Button(25)

## 开关: 光敏开关
BUTTON_LIGHT = Button(14, pull_up=False)       ## , pull_up=False
## 持续多久没有光的时候才会触发


OPERATING = False
REFRESHING = True

LEDS = [LED_S6_RED, LED_S6_GREEN, LED_S7_RED, LED_S7_GREEN, LED_DEMO_RED, LED_DEMO_GREEN, LED_TEST_RED, LED_TEST_GREEN, LED_S9_RED, LED_S9_GREEN, LED_POWER_RED, LED_POWER_GREEN]

## 光敏电阻检测到开灯次数(光敏电阻=False)
IDR_CNT : int = 0

#cmd_script = "script -f logs/" + datetime.datetime.now().strftime("%Y%m%d") + ".log"
#print(cmd_script)
## vm_execshell(cmd_script)
## os.system(cmd_script)
#os.popen(cmd_script, mode='r', buffering=-1)

def current_timestamp() :
    """
        返回当前时间戳的字符串, 带3位毫秒
    """
    return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]


DATES = {}
def checkforshutdown(date = None) -> bool:
    """
    检查今天该不该关机
    """
    global DATES
    if date is None :
        date = datetime.datetime.now().strftime("%Y-%m-%d")
    if os.path.exists("date.txt") :
        if len(DATES) == 0 :
            datefile = open("date.txt", mode="r")
            lines = datefile.readlines()
            for line in lines :
                line = line.replace("\n", "")
                ss = line.split("\t")
                d = ss[0]
                ok = int(ss[1])
                DATES[d] = ok
            datefile.close()
            print(DATES)
        print("today:", date)
        today = date
        if today in DATES.keys() :
            print(today,DATES[today])
            if DATES[today] == 1 :
                return True
            else :
                return False
        else :
            return False
    return False


def init_LED() :
    ## 关闭所有IO口
    ## LED全部都是作为IO口模拟地线,因此是全部打开(高阻态)
    LED_S6_RED.off()
    LED_S6_GREEN.off()
    LED_S7_RED.off()
    LED_S7_GREEN.off()
    LED_DEMO_RED.off()
    LED_DEMO_GREEN.off()
    LED_TEST_RED.off()
    LED_TEST_GREEN.off()
    LED_S9_RED.off()
    LED_S9_GREEN.off()
    LED_POWER_RED.off()
    LED_POWER_GREEN.off()


def init() :
    ## 关闭所有IO口
    ## LED全部都是作为IO口模拟地线,因此是全部打开(高阻态)
    init_LED()
    # BUTTON_AUTOON.close()
    # BUTTON_MANUAL_START.close()
    # BUTTON_MANUAL_STOP.close()





def test() :
    BEEP.off()
    time.sleep(0.5)
    BEEP.on()
    LED_S6_RED.on()
    ## LED_POWER_RED.blink(on_time=0.5, off_time=0.5, n=3)
    LED_S7_RED.on()
    LED_DEMO_RED.on()
    LED_TEST_RED.on()
    LED_S9_RED.on()
    LED_POWER_RED.on()
    time.sleep(2)
    LED_S6_RED.off()
    LED_S7_RED.off()
    LED_DEMO_RED.off()
    LED_TEST_RED.off()
    LED_S9_RED.off()
    LED_POWER_RED.off()
    #LED_POWER_GREEN.off()
    time.sleep(2)
    BEEP.off()
    time.sleep(0.1)
    BEEP.on()
    time.sleep(0.1)
    BEEP.off()
    time.sleep(0.1)
    BEEP.on()
    LED_S6_GREEN.on()
    LED_S7_GREEN.on()
    LED_DEMO_GREEN.on()
    LED_TEST_GREEN.on()
    LED_S9_GREEN.on()
    LED_POWER_GREEN.on()
    time.sleep(100)
    LED_S6_GREEN.off()
    LED_S7_GREEN.off()
    LED_DEMO_GREEN.off()
    LED_TEST_GREEN.off()
    LED_S9_GREEN.off()
    LED_POWER_GREEN.off()
    time.sleep(10)
init()


def all_red() :
    LED_S6_RED.on()
    LED_S7_RED.on()
    LED_S9_RED.on()
    LED_DEMO_RED.on()
    LED_TEST_RED.on()
    LED_POWER_RED.on()



def all_green() :
    LED_S6_GREEN.on()
    LED_S7_GREEN.on()
    LED_S9_GREEN.on()
    LED_DEMO_GREEN.on()
    LED_TEST_GREEN.on()
    LED_POWER_GREEN.on()




def check_server_state() :
    """
    检查服务器电源和虚拟机状态,刷新LED状态
    注意LED灯的on和off相反
    """
    ## 所有灯都先灭掉
    global REFRESHING
    global OPERATING

    if OPERATING :
        print(current_timestamp(), "OPERATING ... IGNORE ")
        return

    REFRESHING = True

    print(current_timestamp(), "STARTING CHECKING POWERS AND VMS STATUS ...")

    init_LED()

    try :
        ## 主板电源
        bs = board_powerstatus()
        if bs == "on" :
            LED_POWER_GREEN.on()
            if BUTTON_LIGHT.is_active :
                print(current_timestamp(), "光敏电阻开关 已激活 ... ")
                handle_button_light()
            else :
                print(current_timestamp(), "光敏电阻开关 未激活 ... ")

            print(current_timestamp(), "POWER ACTIVED, CHECKING VMS STATUS ...")


        else :
            ## LED_POWER_RED.on()
            all_red()
            print(current_timestamp(), "POWER DEACTIVED ...")
            if check_ip_alive() :
                ## 192.168.0.172在线, 而且在上班时间内, 才响
                now = datetime.datetime.now()
                if now.hour >= 8 and now.hour <= 24 :
                    ## 192.168.0.172在线, 而且在上班时间内, 才响
                    BEEP.on()
                    time.sleep(0.1)
                    BEEP.off()
                    time.sleep(0.1)
            REFRESHING = False
            time.sleep(10)
            return

        try :
            vms = vm_list_active_tolist()
        except BaseException as e :
            LED_S6_RED.on()
            LED_S7_RED.on()
            LED_S9_RED.on()
            LED_DEMO_RED.on()
            LED_TEST_RED.on()
            print(current_timestamp(), "ALL VMS DOWN!")
            REFRESHING = False
            return
            
        if NAME_SERVER6 not in vms :
            LED_S6_RED.on()
            print(current_timestamp(), "SERVER6 DOWN...")
        else :
            LED_S6_GREEN.on()
            print(current_timestamp(), "SERVER6 ACTIVED...")
        ## Server7
        if NAME_SERVER7 not in vms :
            LED_S7_RED.on()
            print(current_timestamp(), "SERVER7 DOWN...")
        else :
            LED_S7_GREEN.on()
            print(current_timestamp(), "SERVER7 ACTIVED...")
            
        ## 演示
        if NAME_演示 not in vms :
            LED_DEMO_RED.on()
            print(current_timestamp(), "演示 DOWN...")
        else :
            LED_DEMO_GREEN.on()
            print(current_timestamp(), "演示 ACTIVED...")
        ## 实施
        if NAME_实施 not in vms :
            LED_TEST_RED.on()
            print(current_timestamp(), "实施 DOWN...")
        else :
            LED_TEST_GREEN.on()
            print(current_timestamp(), "实施 ACTIVED...")
        ## Server9
        if NAME_Server9 not in vms :
            LED_S9_RED.on()
            print(current_timestamp(), "Server9 DOWN...")
        else :
            LED_S9_GREEN.on()
            print(current_timestamp(), "Server9 ACTIVED...")
    except Exception as e :
        LED_POWER_RED.on()
        print(current_timestamp(), "POWER DOWN !")
        REFRESHING = False
        return
    REFRESHING = False

def handle_button_power() :
    """
    处理按下电源按钮
    """
    global OPERATING
    print(current_timestamp(), "PRESS POWER")
    OPERATING = True
    ## 如果还没开机就开机
    s = board_powerstatus()
    if s == "on" :
        print("TO POWER OFF")
        poweroff()
    else :
        board_poweron()
    ## 如果已经开了就关掉
    print(current_timestamp(), "完成电源按钮")

    OPERATING = False

## 光敏电阻监测到关灯多少次. 超过600次, 而且HOUR IN (22,23,0,1,2,3,4,5,6,7就关机
LIGHT_OFF_SECOND = 0
def handle_button_light() :
    """
    处理光敏传感器
    """
    global LIGHT_OFF_SECOND
    LIGHT_OFF_SECOND += 1
    print(current_timestamp(), "光敏电阻监测到关灯")
    if LIGHT_OFF_SECOND > 0 :
        now = datetime.datetime.now()
        ok = check_ip_alive()
        c : bool = checkforshutdown()
        if not c :
            print("今天按计划不需要关服务器...")
            return
        if ( now.hour >= 0 and now.hour <= 5 ) and not ok :
            activevms = vm_list_active_tolist()
            if NAME_SERVER7 in activevms :
                print(current_timestamp(), "光敏电阻检测到关灯,而且在0点到5点之间, 而且192.168.0.172b不在线, 尝试关机")
                handle_button_stop()
            else :
                print(current_timestamp(), "光敏电阻检测到关灯,而且192.168.0.172不在线, 不需要关机")
        else :
            if not ( now.hour >= 0 and now.hour <= 5 ) :
                print(current_timestamp(), "光敏电阻检测到关灯但时间范围不符合(晚上00~05点之间), 忽略")
            if ok :
                print(current_timestamp(), "光敏电阻检测到关灯, 但IP在线, 忽略")
        
    
    

def handle_button_start() :
    """
    处理按下开机按钮
    """
    global OPERATING
    print(current_timestamp(), "PRESS START")
    OPERATING = True
    ## vm_poweron_normal()
    start("auto")
    ## time.sleep(20)
    OPERATING = False
    print(current_timestamp(), "DONE PRESS START")

def handle_button_stop() :
    """
    处理按下关机按钮
    """
    global OPERATING
    print(current_timestamp(), "PRESS STOP")
    OPERATING = True
    ## vm_shutdown_all()
    print("TO SHUTDOWN OFF")
    ## stop("all")
    poweroff()
    ##time.sleep(20)
    OPERATING = False
    print(current_timestamp(), "DONE PRESS STOP")

DEVICE_IP = "192.168.0.172"
def check_ip_alive(ip : str = DEVICE_IP) -> bool :
    ping_response = subprocess.run(["ping", "-c", "1", ip], stdout = subprocess.PIPE)
    if ping_response.returncode == 0 :
        ## print("IP ALIVE")
        return True
    else :
        ## print("IP DEAD")
        return False



def auto_start() :
    """
    自动开机,在特定条件下 (检查到特定电脑在线,而且处于上班时间内. 不能自动关机)
    检查到IP 192.168.0.172在线, 而且是上班时间内(8:00~22:00),如果服务器没开, 就自动开
    """
    global IDR_CNT
    now = datetime.datetime.now()
    if now.hour >= 7 and now.hour <= 8 :
        print(current_timestamp(), "working hour... starting checking ip online ...")
        ## 检查IP 192.168.0.172是否在线
        ## 2024-08-30 F 只要开灯了就开服务器
        ## 限制为: 只在早上7,8点之间 (07:00~08:59)检查; 而且光敏电阻开关连续5分钟检测到开灯, 才会开机
        light = BUTTON_LIGHT.is_active
        if not light :
            ## 监测到开灯
            IDR_CNT += 1
        else :
            ## 检测到关灯, 重置
            IDR_CNT = 0
        ipalive = check_ip_alive()
        print("光敏电阻开关状态", light, "IDR_CNT:", IDR_CNT, "IPALIVE:", ipalive)

        ## if ( not BUTTON_LIGHT.is_active ) or check_ip_alive() :
        if IDR_CNT >= 5 or  ipalive:
            ## 检查服务器状态
            # print(current_timestamp(), "IDR_CNT:", IDR_CNT, ",IP_ALIVE:")
            ## vms = vm_list_active_tolist()
            ## if NAME_SERVER7 not in vms :
            ss = check_ip_alive("192.168.0.248")
            print(current_timestamp(), "server7 state :", ss)
            if not  ss:
                print(current_timestamp(), "服务器没开! 自动打开...")
                start("auto")
            else :
                print(current_timestamp(), "SERVER ACTIVED. NO NEED TO START IT")

        




class CheckServerState(threading.Thread) :
    def __init__(self) :
        threading.Thread.__init__(self)
        self.daemon = True
        self.start()

    def run(self) :
        global OPERATING
        while True :
            if OPERATING :
                all_red()
                all_green()
                time.sleep(1)
                init_LED()
                time.sleep(1)
                check_server_state()
                time.sleep(1)
            else :
                check_server_state()
                i = 0
                while i < 60 and not OPERATING :
                    time.sleep(1)
                    i += 1
            # test()
            # time.sleep(10)
            # start_check_server_state()
           # time.sleep(10)

class AutoStart(threading.Thread) :
    def __init__(self) :
        threading.Thread.__init__(self)
        self.daemon = True
        self.start()

    def run(self) :
        global OPERATING
        while True :
            if BUTTON_AUTOON.value == 1 and not OPERATING:
                now = datetime.datetime.now()
                if now.hour >= 7 and now.hour <= 7 :
                    ## 检查IP 192.168.0.172是否在线
                    print(current_timestamp(), "AUTO ON HELD, GOTING TO CHECKING AUTO START SERVER ...")
                    auto_start()
                else :
                    print(current_timestamp(), "AUTO ON HELD, BUT NOT IN WORKING HOUR, IGNORE")
            
            ## print("AUTO ON NOT HELD")
            time.sleep(60)



class Bling(threading.Thread) :
    def __init__(self) :
        threading.Thread.__init__(self)
        self.daemon = True
        self.start()

    def run(self) :
        global REFRESHING
        global OPERATING

        second = 0.1
        while True :
            if not REFRESHING and not OPERATING :
                led = random.choice(LEDS)
                ## print(led, led.is_active)
                if led.is_active :
                    led.off()
                    time.sleep(0.1)
                    led.on()
            time.sleep(second)



BUTTON_MANUAL_START.when_activated = handle_button_start
BUTTON_MANUAL_STOP.when_activated = handle_button_stop
BUTTON_POWER.when_activated = handle_button_power
## BUTTON_LIGHT.when_activated = handle_button_light
## BUTTON_LIGHT.when_held = handle_button_light()
## BUTTON_LIGHT.when_activated = handle_button_light


a = CheckServerState()
b = AutoStart()
c = Bling()

while True :
    # check_server_state()
    # # test()
    # time.sleep(10)
    ## start_check_server_state()
    time.sleep(1)